#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5; // Trie树的最大节点数
int ans, idx, id, tr[N][26]; // ans: 当前未匹配的Y字符串数; idx: Trie节点计数器;
                             // id: Y字符串ID计数器
vector<int> pos[N];   // 记录每个Trie节点上存储的Y字符串ID
bool flag[N], vis[N]; // flag: 标记是否是X字符串终点; vis: 标记Y字符串是否已匹配

// 插入X集合字符串
void insert1(string str) {
  int p = 0; // 从Trie根节点开始
  for (auto c : str) {
    int ch = c - 'a'; // 字符转换为0-25的索引
    if (!tr[p][ch])   // 如果子节点不存在则创建
      tr[p][ch] = ++idx;
    p = tr[p][ch]; // 移动到子节点
  }
  flag[p] = 1; // 标记当前节点为X字符串终点
  // 处理该节点上所有未匹配的Y字符串
  for (auto x : pos[p])
    if (!vis[x])         // 如果Y字符串x未被匹配过
      vis[x] = 1, ans--; // 标记为已匹配并减少未匹配计数
  pos[p].clear();        // 清空该节点的Y字符串ID列表
}

// 插入Y集合字符串
void insert2(string str) {
  int p = 0;
  ++id;  // 分配新的Y字符串ID
  ans++; // 增加未匹配计数
  for (auto c : str) {
    int ch = c - 'a';
    if (!tr[p][ch])
      tr[p][ch] = ++idx;
    p = tr[p][ch];
    pos[p].push_back(id); // 在当前节点记录Y字符串ID
    // 如果当前节点是X字符串终点且Y字符串未被匹配
    if (!vis[id] && flag[p]) {
      vis[id] = 1; // 标记为已匹配
      ans--;       // 减少未匹配计数
    }
  }
}

int main() {
  int n;
  cin >> n; // 读取操作数量
  for (int i = 1; i <= n; i++) {
    int op;
    string str;
    cin >> op >> str; // 读取操作类型和字符串
    if (op == 1)      // 操作1: 插入X字符串
      insert1(str);
    if (op == 2) // 操作2: 插入Y字符串
      insert2(str);
    cout << ans << endl; // 输出当前未匹配的Y字符串数量
  }
  return 0;
}